package chessBoard;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;

import javax.swing.JPanel;

import org.apache.log4j.Logger;

import connection.Reader;

/**
 * Panel na kterem je sachovnicova plocha
 * 
 * @author dove
 * 
 */
public class BoardPanel extends JPanel {

	private static final long serialVersionUID = 1L;
	private int height = 48;
	private int width = 48;

	private boolean red = false;

	private boolean[][] isPressed = new boolean[8][8];
	private boolean[][] moves = new boolean[8][8];
	private String[][] positions = new String[8][8];

	private int[][] memory = new int[2][2];
	private BufferedWriter bw;

	private String from = "";
	private int which = 0;

	private int[] reverse = { 8, 7, 6, 5, 4, 3, 2, 1 };
	private int[] reverse3 = { 1, 2, 3, 4, 5, 6, 7, 8 };
	private int[] reverse2 = { 7, 6, 5, 4, 3, 2, 1, 0 };
	private int[] reverse4 = { 0, 1, 2, 3, 4, 5, 6, 7 };

	private Color white = new Color(209, 205, 184);
	private Color black = new Color(110, 129, 158);

	private Dimension boardSize = new Dimension(height * 8, width * 8);

	private Hashtable<String, Image> pieces = new Hashtable<String, Image>();

	private boolean flip = true;
	private String piecesPath = System.getProperty("user.dir") + File.separator
			+ "Resources" + File.separator + "pieces" + File.separator;

	private String draggedPiece = "";
	private int dragX;
	private int dragY;

	private static Logger logger = Logger.getLogger("Log");

	/**
	 * Nastavuje sachovnici
	 */
	public BoardPanel() {
		pieces.put("p", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "bp.png"));
		pieces.put("k", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "bk.png"));
		pieces.put("q", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "bq.png"));
		pieces.put("b", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "bb.png"));
		pieces.put("r", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "br.png"));
		pieces.put("n", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "bn.png"));
		pieces.put("P", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "wp.png"));
		pieces.put("K", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "wk.png"));
		pieces.put("Q", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "wq.png"));
		pieces.put("B", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "wb.png"));
		pieces.put("R", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "wr.png"));
		pieces.put("N", Toolkit.getDefaultToolkit().getImage(
				piecesPath + "wn.png"));

		bw = Reader.getWriter();
		for (int i = 0; i < 8; i++) {
			for (int j = 0; j < 8; j++) {
				positions[i][j] = "-";
			}
		}

		this.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				if (e.getButton() == 1) {
					if (!positions[e.getX() / width][e.getY() / height]
							.equals("-")) {
						draggedPiece = positions[e.getX() / width][e.getY()
								/ height];
						positions[e.getX() / width][e.getY() / height] = "-";
					}
					logger.debug("DRAGED " + draggedPiece);
					dragX = e.getX();
					dragY = e.getY();
					pressed(e);
				} else if (e.getButton() == 3) {
					mouseClicked(e);
				}
			}
		});

		addMouseMotionListener(new MouseMotionAdapter() {
			public void mouseDragged(MouseEvent e) {
				drag(e);
			}
		});

		addMouseListener(new MouseAdapter() {
			public void mouseReleased(MouseEvent e) {
				drop(e);
			}
		});

		this.setSize(boardSize);
	}

	private void drag(MouseEvent e) {
		dragX = e.getX();
		dragY = e.getY();
		repaint();
	}

	private void drop(MouseEvent e) {
		positions[e.getX() / width][e.getY() / height] = draggedPiece;
		draggedPiece = "";
		pressed(e);
		logger.debug("DROP");
	}

	/**
	 * Obnoveni cele sachovnice
	 */
	public void update() {
		updateUI();
		this.updateUI();
	}

	/**
	 * Nastavuje pozice figur na sachovnici
	 * 
	 * @param positions
	 *            pozice figur
	 */
	public void setPositions(String[][] positions) {
		if (flip) {
			this.positions = positions;
		} else {
			for (int i = 0; i < positions.length; i++) {
				for (int j = 0; j < positions.length; j++) {
					this.positions[i][j] = positions[i][reverse2[j]];
				}
			}
		}
		repaint();
	}

	/**
	 * Zjistuje stisknuti sachoveho pole
	 * 
	 * @param x
	 *            pozice pole
	 * @param y
	 *            pozice pole
	 * @return je stisknuto
	 */
	public boolean getPressed(int x, int y) {
		return isPressed[x][y];
	}

	/**
	 * Prepina stisknuti sachoveho pole
	 * 
	 * @param x
	 *            pozice pole
	 * @param y
	 *            pozice pole
	 */
	public void switchPressed(int x, int y) {
		isPressed[x][y] = !isPressed[x][y];
		repaint();
	}

	private void pressed(MouseEvent arg0) {
		logger.debug(arg0.getX() + "," + arg0.getY());

		if (arg0.getX() < boardSize.width && arg0.getY() < boardSize.height) {
			switchPressed(arg0.getX() / width, arg0.getY() / height);
			logger.debug(arg0.getX() + "," + arg0.getY());
			System.out
					.println(arg0.getX() / width + "," + arg0.getY() / height);
			red = getPressed(arg0.getX() / width, arg0.getY() / height);
			memory[which][0] = arg0.getX();
			memory[which][1] = arg0.getY();

			if (flip) {
				from = from.concat(Convertor
						.numberToLetter((arg0.getX() + width) / width));
				from = from
						.concat(String
								.valueOf(reverse[((arg0.getY() + height) / height) - 1]));
			} else {
				from = from.concat(Convertor
						.numberToLetter((arg0.getX() + width) / width));
				from = from
						.concat(String
								.valueOf(reverse3[((arg0.getY() + height) / height) - 1]));
			}
			logger.debug("FROM:!!!!!!" + from);

			if (red) {
				which++;
			} else {
				which--;
				from = from.substring(0, from.length() - 4);
			}
			if (which > 1) {
				if (Reader.isConnect()) {
					try {
						bw.write(from + "\n");
						bw.flush();
					} catch (IOException e) {
						logger.error("", e);
					}
				}
				from = "";
				which = 0;
				switchPressed(memory[0][0] / width, memory[0][1] / height);
				switchPressed(memory[1][0] / width, memory[1][1] / height);
			}
		}
	}

	public void paint(Graphics g) {

		int a = 0;

		Color[] colors = { white, black };

		for (int y = 0; y < height * 8; y += height) {
			for (int x = 0; x < width * 8; x += width) {
				g.setColor(colors[a % 2]);
				if (isPressed[x / width][y / height] == true) {
					g.setColor(new Color(0, 0, 190));
				} else if (moves[x / width][y / height] == true) {
					g.setColor(Color.BLUE);
				}
				g.fillRect(x, y, width, height);
				a++;
			}
			a++;
		}
		int desetina = width / 20;

		for (int y = 0; y < height * 8; y += height) {
			for (int x = 0; x < width * 8; x += width) {
				g.setColor(colors[a % 2]);
				g.fillRect(x + desetina, y + desetina, width - (2 * desetina),
						height - (2 * desetina));
				a++;
			}
			a++;
		}

		for (int y = 0; y < height * 8; y += height) {
			for (int x = 0; x < width * 8; x += width) {
				if (positions[x / width][y / height] != null) {
					g.drawImage(pieces.get(positions[x / width][y / height]),
							x, y, width, height, null);
				}
			}
		}

		if (!draggedPiece.equals("")) {
			g.drawImage(pieces.get(draggedPiece), dragX - height / 2, dragY
					- width / 2, width, height, null);
		}
	}

	/**
	 * Nastavuje stisknuti sachoveho pole
	 * 
	 * @param x
	 *            pozice pole
	 * @param y
	 *            pozice pole
	 */
	public void setPressed(int x, int y) {
		if (flip) {
			moves[x][reverse2[y]] = true;
		} else {
			moves[x][reverse4[y]] = true;
		}
		repaint();
	}

	/**
	 * 
	 * Vypina stisknuti sachoveho pole
	 * 
	 * @param x
	 *            pozice pole
	 * @param y
	 *            pozice pole
	 */
	public void unsetPressed(int x, int y) {
		if (flip) {
			moves[x][reverse2[y]] = false;
		} else {
			moves[x][reverse4[y]] = false;
		}
		repaint();
	}

	/**
	 * Vraci jestli je sachovnice otocena
	 * 
	 * @return true jestlize je otocena false jestlize neni otocena
	 */
	public boolean getFlip() {
		return flip;
	}

	/**
	 * Nastavuje orientaci sachovnice
	 * 
	 * @param flip
	 *            bile dole
	 */
	public void setFlip(boolean flip) {
		this.flip = flip;
		repaint();
	}

	public Dimension getSize() {
		return boardSize;
	}

	/**
	 * Nastavuje velikost jednoho sachovnicoveho pole
	 * 
	 * @param size
	 *            velikost pole
	 */
	public void setFieldSize(Dimension size) {
		boardSize = new Dimension(size.width * 8, size.height * 8);
		this.setSize(boardSize);
		width = size.width;
		height = size.height;
		repaint();
	}
}
